package FreebaseMatchWiki;

import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import raphaelMatcher.*;
import java.util.*;

class TypePropValue {
	String type;
	String prop;
	String value;

	public TypePropValue(String type, String prop, String value) {
		this.type = type;
		this.prop = prop;
		this.value = value;
	}
}

class WpidGuidNameType{
	int wpid;
	String guid;
	String name;
	String type;
	String prop;
	String value;
	public WpidGuidNameType(int wpid, String guid, String name, String type, String prop, String value) {
		this.wpid = wpid;
		this.guid = guid;
		this.name = name;
		this.type = type;
		this.prop = prop;
		this.value = value;
	}
	public String toString(){
		return wpid+"\t"+guid+"\t"+name+"\t"+type+"\t"+prop+"\t"+value;
	}
}
class MyDB {
	Connection conn;

	// Statement stmt;

	public MyDB() {
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();

			conn = DriverManager.getConnection(
					"jdbc:mysql://pardosa06.cs.washington.edu/freebase",
					"clzhang", "wiki");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
//	public void getAllTypePropValueWithWpid(){
//		String query = "select G.wpid, T.type, T.prop, T.value from type T, guid_wpid G where G.guid=T.guid";
//		ArrayList<TypePropValue> tpvlist = new ArrayList<TypePropValue>();
//		try{
//			Statement stmt = conn.createStatement();
//			ResultSet res = stmt.executeQuery(query);
//			while(res.next()){
//				String wpid = res.getString("wpid");
//				String type = res.getString("type");
//				String prop = res.getString("prop");
//				String value = res.getString("value");
//				//String value = rawValue2String(rawValue, entityname);
////				if (value.length() > 0 && value.length() < 2000) {
////					TypePropValue tpv = new TypePropValue(type, prop, value);
////					tpvlist.add(tpv);
////				}
//			}
//		}catch(Exception e){
//			
//		}
//		
//	}
	public ArrayList<TypePropValue> getTypePropValueWithWpid(int wpid,
			String entityname) {
		String query = "select T.type, T.prop, T.value from type T, guid_wpid G where G.wpid="
				+ wpid + " AND G.guid=T.guid";
		ArrayList<TypePropValue> tpvlist = new ArrayList<TypePropValue>();
		try {
			Statement stmt = conn.createStatement();
			ResultSet res = stmt.executeQuery(query);
			while (res.next()) {
				String type = res.getString("type");
				String prop = res.getString("prop");
				String rawValue = res.getString("value");
				String value = rawValue2String(rawValue, entityname);
				if (value.length() > 0 && value.length() < 2000) {
					TypePropValue tpv = new TypePropValue(type, prop, value);
					tpvlist.add(tpv);
				}
			}
			res.close();
			stmt.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return tpvlist;
	}
	public ArrayList<WpidGuidNameType> getWpidGuidNameType(int wpid){
		String query = "select G.wpid, G.guid, GN.name, T.type, T.prop, T.value from type T, guid_wpid G, guid_name GN where G.wpid="+wpid+" AND G.guid=T.guid AND GN.guid=T.guid";
		ArrayList<WpidGuidNameType> tpvlist = new ArrayList<WpidGuidNameType>();
		try {
			Statement stmt = conn.createStatement();
			ResultSet res = stmt.executeQuery(query);
			while (res.next()) {
				String guid = res.getString("guid");
				String name = res.getString("name");
				String type = res.getString("type");
				String prop = res.getString("prop");
				String value = res.getString("value");
				if (value.length() > 0 && value.length() < 2000) {
					WpidGuidNameType tpv = new WpidGuidNameType(wpid,guid,name,type, prop, value);
					tpvlist.add(tpv);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return tpvlist;
	}
	public String getValueFromType(String guid, String entityname) {
		String retval = "";

		try {
			Statement stmt = conn.createStatement();
			ResultSet res = stmt
					.executeQuery("select value from type where guid='" + guid
							+ "'");
			while (res.next()) {
				String value = res.getString("value");
				if (!value.equals(entityname)) {
					retval += value + "|";
				}
			}
		} catch (Exception e) {

		}
		return retval;
	}

	public String rawValue2String(String raw, String entityname) {
		String result = "";
		// String result = "";
		String[] abc = raw.split(",");
		for (int i = 0; i < abc.length; i++) {
			if (abc[i].contains("/guid/")) {
				String query = abc[i].replace("/guid/", "");
				result += getValueFromType(query, entityname);
			} else {
				result += abc[i] + "|";
			}
		}
		return result;
	}
}

/**
 * select T.type, T.prop, T.value from type T, guid_wpid G where G.wpid=12 AND
 * G.guid=T.guid For Anarchism
 */
public class ExtractFBTypeValueParallel {

	static HashMap<String, Integer> typeprop_id = new HashMap<String, Integer>();
	static int MAXAllowMatchOneProperty = 10;
	static int MAXAllowPropNumber = 10; //I only allow one property has ** values, if it has more than that value, there is no hope to match in context
	static int NODES = 10;
	public static void load_typeprop_id(String file) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(
				new FileInputStream(file)));
		String line = "";
		int ln = 1;
		while ((line = br.readLine()) != null) {
			String[] abc = line.split("\\s");
			String typeprop = abc[1] + "\t" + abc[2];
			typeprop_id.put(typeprop, ln++);
		}
	}

	/**
	 * @param args
	 */
	//main_main
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		String rphid_wpid_file = args[0];
		String sentence_file = args[1];
		load_typeprop_id(args[2]);
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
				args[3]), "utf-8");
		//DelimitedWriter dw = new DelimitedWriter(args[3]);
		int parallelId = Integer.parseInt(args[4]);
		DelimitedWriter dwlog = new DelimitedWriter("log."+parallelId+".txt");
		DelimitedReader br = new DelimitedReader(rphid_wpid_file);
		DelimitedReader brsen = new DelimitedReader(sentence_file);
		
		
		String line = "";
		MyDB mydb = new MyDB();
		String line2 = "";

		ArrayList<String[]> block = new ArrayList<String[]>();
		String[] buffer = null;
		int ln = 0;
		
		while (true) {
			ln++;
			if (ln % 100 == 0)
				System.out.print(".");
			if (ln % 10000 == 0)
				System.out.println((new java.util.Date()).toString()+"  "+ln);	
			//line = br.readLine();
			

			// line = "240	736	Albert Einstein";
			String []abc = null;
			try{
				abc = br.read();
				if(abc == null) break;
			}catch(Exception e){
				dwlog.write("rphid_wpid_file line number",ln+"");
				continue;
			}
			
			int rphid = Integer.parseInt(abc[0]);
			int wpid = Integer.parseInt(abc[1]);
			String title = abc[2];
			if(rphid % NODES != parallelId)continue;
			block.clear();
			if (buffer != null
					&& Integer
							.parseInt(buffer[raphaelMatcher.CreateSentencesSchema.cs_articleId]) == wpid) {
				block.add(buffer);
			}
			while (true) {
				String []sensplit=null;
				try{
					sensplit = brsen.read();
					if(sensplit == null)break;
				}catch(Exception e){
					dwlog.write("sentence file, rphid",rphid+"");
					continue;
				}
				int senrphid = Integer
						.parseInt(sensplit[raphaelMatcher.CreateSentencesSchema.cs_articleId]);

				if (senrphid == rphid) {
					block.add(sensplit);
				} else if (senrphid > rphid) {
					buffer = sensplit;
					break;
				}
			}

			ArrayList<TypePropValue> tpvlist = mydb.getTypePropValueWithWpid(
					wpid, abc[2]);
			
			for (TypePropValue tpv : tpvlist) {
				ArrayList<String> toWrite = new ArrayList<String>();
				for (String[] sensplit : block) {
					String value = tpv.value;
					String sentence = sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentence];
					int senid = Integer
							.parseInt(sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentenceId]);
					ArrayList<Integer> matchPos = strictAndCapitalMatch(value,
							sentence, title);
					if (matchPos != null && matchPos.size() > 0) {
						toWrite.add(rphid + "\t" + wpid + "\t" + senid + "\t"
								+ tpv.type + "\t" + tpv.prop + "\t" + matchPos
								+ "\t" + value);
						if (toWrite.size() > MAXAllowMatchOneProperty) {
							break;
						}
					}
				}
				if (toWrite.size() <= MAXAllowMatchOneProperty) {
					for (String a : toWrite)
						osw.write(a+"\n");
				}
			}
			// break;
		}
		br.close();
		osw.close();
		dwlog.close();
	}

	public static ArrayList<Integer> strictMatch(String value, String sentence) {

		ArrayList<Integer> res = new ArrayList<Integer>();
		String[] abc = value.toLowerCase().split("\\|");
		sentence = sentence.toLowerCase();
		boolean completeMatch = true;
		for (int i = 0; i < abc.length; i++) {
			int a = sentence.indexOf(abc[i]);
			if (a >= 0) {
				res.add(a);
				// System.out.println(value+"\t"+sentence);
			} else {
				completeMatch = false;
				break;
			}
		}
		if (completeMatch) {
			return res;
		} else {
			return null;
		}
	}

	public static ArrayList<Integer> strictAndCapitalMatch(String value,
			String sentence, String title) {

		ArrayList<Integer> res = new ArrayList<Integer>();
		String[] abc = value.split("\\|");
		sentence = sentence.toLowerCase();
		boolean matchCaptialLetter = false;
		if (abc.length > MAXAllowPropNumber) {
			return null;
		}
		for (int i = 0; i < abc.length; i++) {
			int a = sentence.indexOf(abc[i].toLowerCase());

			if (a >= 0) {
				res.add(a);
				String[] aa = abc[i].split("\\s");
				// if contain capital letter && title not contain that word &&
				// abc[i] contain at least two words
				//boolean abciLonger5 = abc[i].length() > 5;
				if (!title.contains(abc[i])) {
					matchCaptialLetter = true;
				}
				// System.out.println(value+"\t"+sentence);
			} else {
				res.add(-1);
			}
		}
		boolean allMatch = true;
		for (int a : res) {
			if (a == -1)
				allMatch = false;
		}
		if (matchCaptialLetter || allMatch) {
			return res;
		} else
			return null;
	}

	//main_debug_one
	public static void debug_one(String file, ArrayList<String[]>block, ArrayList<TypePropValue> tpvlist,String title,int rphid,int wpid)
	throws Exception{
		DelimitedWriter osw = new DelimitedWriter(file);
		for (String[] sensplit : block) {
			String sentence = sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentence];
			osw.write(sentence);
		}
		osw
				.write("----------------------------------------------------------------------------------------------------------------------\n");

		for (TypePropValue tpv : tpvlist) {
			osw.write(tpv.type + "\t" + tpv.prop + "\t" + tpv.value);

		}
		osw
				.write("\n----------------------------------------------------------------------------------------------------------------------\n");

		for (TypePropValue tpv : tpvlist) {
			for (String[] sensplit : block) {
				String value = tpv.value;
				String sentence = sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentence];
				int senid = Integer
						.parseInt(sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentenceId]);
				ArrayList<Integer> matchPos = strictAndCapitalMatch(value,
						sentence, title);
				if (matchPos != null && matchPos.size() > 0) {
					osw.write(tpv.type + "\t" + tpv.prop + "\t" + matchPos
							+ "\t" + value + "\t" + sentence + "\n");
					System.out.println(formatOutput(rphid, wpid, senid,
							tpv, matchPos));
				}
			}
		}
	}

	//main_debug
	public static void main_debug(String[] args) throws Exception {
		// TODO Auto-generated method stub
		
		String rphid_wpid_file = args[0];
		String sentence_file = args[1];
		load_typeprop_id(args[2]);
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
				"temp"), "utf-8");
		BufferedReader br = new BufferedReader(new FileReader(rphid_wpid_file));
		BufferedReader brsen = new BufferedReader(new InputStreamReader(
				new FileInputStream(sentence_file), "utf-8"));
		String line = "";
		MyDB mydb = new MyDB();
		String line2 = "";

		ArrayList<String[]> block = new ArrayList<String[]>();
		String[] buffer = null;
		int ln = 0;
		while ((line = br.readLine()) != null && ln < 1000) {
			ln++;
			if (ln % 10 == 0)
				System.out.print(".");
			if (ln % 1000 == 0)
				System.out.println((new java.util.Date()).toString());
			// line = "240	736	Albert Einstein";
			String[] abc = line.split("\t");
			int rphid = Integer.parseInt(abc[0]);
			int wpid = Integer.parseInt(abc[1]);
			String title = abc[2];

			block.clear();
			if (buffer != null
					&& Integer
							.parseInt(buffer[raphaelMatcher.CreateSentencesSchema.cs_articleId]) == wpid) {
				block.add(buffer);
			}
			while ((line2 = brsen.readLine()) != null) {
				String[] sensplit = line2.split("\t");
				int senrphid = Integer
						.parseInt(sensplit[raphaelMatcher.CreateSentencesSchema.cs_articleId]);

				if (senrphid == rphid) {
					block.add(sensplit);
				} else if (senrphid > rphid) {
					buffer = sensplit;
					break;
				}
			}

			ArrayList<TypePropValue> tpvlist = mydb.getTypePropValueWithWpid(
					wpid, abc[2]);

			// for debug
			// for (String[] sensplit : block) {
			// String sentence =
			// sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentence];
			// osw.write(sentence + "\n");
			// }
			// osw
			// .write("----------------------------------------------------------------------------------------------------------------------\n");
			//
			// for (TypePropValue tpv : tpvlist) {
			// osw.write(tpv.type + "\t" + tpv.prop + "\t" + tpv.value + "\n");
			//
			// }
			// osw
			// .write("----------------------------------------------------------------------------------------------------------------------\n");

			for (TypePropValue tpv : tpvlist) {
				ArrayList<String> toWrite = new ArrayList<String>();
				for (String[] sensplit : block) {
					String value = tpv.value;
					String sentence = sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentence];
					int senid = Integer
							.parseInt(sensplit[raphaelMatcher.CreateSentencesSchema.cs_sentenceId]);
					ArrayList<Integer> matchPos = strictAndCapitalMatch(value,
							sentence, title);
					if (matchPos != null && matchPos.size() > 0) {
						toWrite.add(rphid + "\t" + wpid + "\t" + senid + "\t"
								+ tpv.type + "\t" + tpv.prop + "\t" + matchPos
								+ "\t" + value+"\t"+sentence);
						if (toWrite.size() > MAXAllowMatchOneProperty) {
							break;
						}
						// osw.write(rphid+"\t"+wpid+"\t"+senid+"\t"+tpv.type +
						// "\t" + tpv.prop + "\t" + matchPos
						// + "\t" + value + "\n");
						// String toWrite = formatOutput(rphid, wpid, senid,
						// tpv, matchPos);
						// if(toWrite!=null){
						// osw.write(toWrite+"\n");
						// }
					}
				}
				if (toWrite.size() <= MAXAllowMatchOneProperty) {
					for (String a : toWrite)
						osw.write(a + "\n");
				}
			}
			// break;
		}
		br.close();
		osw.close();
	}

	public static String formatOutput(int rphId, int wpid, int sentenceId,
			TypePropValue tpv, ArrayList<Integer> matchpos) {
		int propid = -1;
		try {
			propid = typeprop_id.get(tpv.type + "\t" + tpv.prop);
			return rphId + "\t" + wpid + "\t" + sentenceId + "\t" + propid
					+ "\t" + matchpos.toString();
		} catch (Exception e) {
			// e.printStackTrace();
		}
		return null;

	}

}
